package com.czk.writer;

import com.czk.utils.FileUtil;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;


/**
 * @Author:ChenZhangKun
 * @Date: 2021/9/15 22:19
 */
public class GenerateIf {
    public static void main(String[] args) {
        // 地址
        String path = "F:\\IdeaProjects\\asm\\target\\classes\\com\\czk\\sample\\GenerateIf.class";
        // 生成的字节码字节流
        byte[] bytes = generateIf();
        FileUtil.writeBytes(path, bytes);
    }

    private static byte[] generateIf() {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        // 类
        cw.visit(V1_8, ACC_PUBLIC, "com/czk/sample/GenerateIf", null, "java/lang/Object", null);
        // 构造
        {
            MethodVisitor methodVisitor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            // 开始访问代码
            methodVisitor.visitCode();
            // 加载第一个
            methodVisitor.visitVarInsn(ALOAD, 0);
            // 执行命令
            methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            // 返回
            methodVisitor.visitInsn(RETURN);
            methodVisitor.visitMaxs(1, 1);
            methodVisitor.visitEnd();
        }
        {
            // test方法
            Label elseLabel = new Label();
            Label returnLabel = new Label();
            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "test", "(I)V", null, null);
            mv.visitCode();
            // 加载第二个变量
            mv.visitVarInsn(ILOAD, 1);
            mv.visitInsn(ICONST_1);
            // 是否不等于1就跳转
            mv.visitJumpInsn(IF_ICMPNE, elseLabel);
            // 执行if下面的的语句 这里默认是var==0如果需要var==1,需要自己在前面将1加载到localVariable中
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            // 加载常量进入operate stack
            mv.visitLdcInsn("value is 1");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            // 返回
            mv.visitJumpInsn(GOTO, returnLabel);
            // 执行不成立
            mv.visitLabel(elseLabel);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            // 加载常量进入operate stack
            mv.visitLdcInsn("value is not 1");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            mv.visitLabel(returnLabel);
            mv.visitInsn(RETURN);
            // 要写，asm可以帮助计算
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}
